using System;
using System.IO;
using System.Text;
using System.Collections;
using DesignPatternDefinitions;

namespace CodeGenerators
{
	internal class JavaClassGenerator : IDPAClassGenerator
	{
		#region Members
		private IClass objClass = null;
		private IProjectComponent objComponent = null;
		bool isInterface = false;
		#endregion
		
		#region IDPAClassGenerator Members

		public string GenerateClass(string dirName, IClass objClass, IProjectComponent parent)
		{
			this.objClass = objClass;
			this.objComponent = parent;
			
			string jFilename = dirName + "\\" + objClass.ClassName + ".java";
			GenerateClassFile(jFilename);
			return jFilename;
		}

		#endregion

		#region Implementation
		private void GenerateClassFile( string filename )
		{
			StreamWriter writer = new StreamWriter( filename );
			TemplateProcessor processor = new TemplateProcessor(
				System.Windows.Forms.Application.StartupPath + Constants.TEMPLATEPATH + "\\Template.java"
			);
			processor["ClassName"] = objClass.ClassName;
			processor["ComponentName"] = objComponent.ComponentName;
			processor["ClassSummary"] = objClass.ClassSummary;
			processor["Type"] = GetClassType();
			processor["Specifiers"] = GetSpecifiers();
			processor["BaseClasses"] = GetBaseClasses();
			processor["Aggregates"] = GetAggregates();
			processor["References"] = GetReferences();
			processor["Creates"] = GetCreates();
			processor["Fields"] = GetFields();
			processor["Constructor"] = GetConstructor();
			processor["Methods"] = GetMethods();
			writer.WriteLine(
				processor.Render()
			);
			writer.Close();
		}
		private string GetClassType()
		{
			if ( objClass.GetMetaInfo(Constants.JAVA).IndexOf("interface") != -1 )
			{
				isInterface = true;
				return "interface";
			}
			return "class";
		}
		private string GetSpecifiers()
		{
			StringBuilder builder = new StringBuilder();
			if( objClass.AccessModifier != null && objClass.AccessModifier.Length > 0 )
				builder.Append( objClass.AccessModifier + " ");
			if( objClass.Abstract )
				builder.Append( "abstract ");
			return builder.ToString();
		}
		private string GetBaseClasses()
		{
			StringBuilder builder = new StringBuilder();
			ArrayList inhList = objClass.InheritedClasses;
			if(inhList.Count == 0)
				return "";
			builder.Append("implements ");
			int inhcount = 0;
			foreach(IInheritance inh in inhList) 
			{
				builder.AppendFormat(" {0} ",inh.BaseClass);
				inhcount++;
				if((inhList.Count - inhcount) > 0)
					builder.Append(", ");
			}
			return builder.ToString();
		}
		private string GetAggregates()
		{
			StringBuilder builder = new StringBuilder();
			ArrayList AggregatesList = objClass.Aggregates;

			foreach(IAggregate agg in AggregatesList) 
			{
				string aggFldName = agg.AggregateName;
				if( aggFldName != null && aggFldName==string.Empty)
					aggFldName = "noNameAggField" + AggregatesList.IndexOf(agg);
				string order = agg.Order.ToString();
				
				if (order == "Single")
					builder.AppendFormat("{0} {1};\r\n",agg.AggregateeClass,aggFldName);
				
				bool flag = false;
				if (order == "Multiple") 
				{
					if(!flag) 
					{
						builder.AppendFormat("Vector {0} = new Vector();",aggFldName);
						flag = true;
					}
					else 
					{
						builder.AppendFormat("Vector.addElement(");
						builder.AppendFormat(" {0} )\r\n",agg.AggregateeClass);
					}
				}
			}
			return builder.ToString();
		}
		private string GetReferences()
		{
			StringBuilder builder = new StringBuilder();
			ArrayList ReferencesList = objClass.References;
			if(ReferencesList.Count > 0)
			foreach(IReference ir in ReferencesList) 
					builder.AppendFormat("{0} in {1}\r\n",ir.ReferedClassName,ir.ReferenceComponent);
			return builder.ToString();
		}
		private string GetCreates()
		{
			StringBuilder builder = new StringBuilder();
			ArrayList CreatesList = objClass.Creations;
			if(CreatesList.Count>0)
				foreach(ICreation ic in CreatesList) 
					builder.AppendFormat(" {0} in {1}\r\n",ic.CreateeClassName,ic.CreateeComponentName);
			return builder.ToString();
		}
		private string GetFields()
		{
			StringBuilder builder = new StringBuilder();
			ArrayList FieldsList = objClass.Fields;
			
			if(isInterface) 
				builder.Append("/** Initialize these fields before compiling! */");

			foreach(IField field in FieldsList) 
			{
				builder.AppendFormat("\t/** {0} */\r\n", field.FieldSummary );
				builder.AppendFormat(
					"\t{0} {1} {2} {3};\r\n",
					field.GetMetaInfo(Constants.JAVA),
					field.FieldVisibility,
					field.FieldType,
					field.FieldName
				);
			}
			return builder.ToString();
		}
		private string GetConstructor()
		{
			if( isInterface )
				return "";
			
			StringBuilder builder = new StringBuilder();
			builder.AppendFormat( "public {0}()\r\n\t{{\r\n\t}}" , objClass.ClassName );
			return builder.ToString();
		}
		private string GetMethods()
		{
			StringBuilder builder = new StringBuilder();
			ArrayList MethodsList = objClass.Methods;
			foreach(IMethod method in MethodsList)
			{
				builder.AppendFormat("\t/** {0} */\r\n",method.MethodSummary);
				if(method.MethodType == MethodType.Abstract)
					builder.AppendFormat(
						"\tabstract {0} {1} {2} {3} (",
						method.GetMetaInfo(Constants.JAVA),
						method.MethodVisibility,
						method.MethodReturnType,
						method.MethodName
					);
				else
					builder.AppendFormat(
						"\t{0} {1} {2} {3} (",
						method.GetMetaInfo(Constants.JAVA),
						method.MethodVisibility,
						method.MethodReturnType,
						method.MethodName
					);
				ArrayList ParametersList = method.Parameters;
				int pIndex = 0;
				foreach(IParameter parameter in ParametersList) 
				{
					builder.AppendFormat(
						"{0} {1} {2}",
						parameter.GetMetaInfo(Constants.JAVA),
						parameter.ParameterType,
						parameter.ParameterName
					);
					++pIndex;
					if (ParametersList.Count - pIndex > 0)
						builder.Append(", ");
				}
				builder.Append(")");
				if( method.MethodType== MethodType.Abstract || isInterface )
					builder.Append(";");
				else
					builder.Append("\r\n\t{\r\n\t}");
				builder.Append("\r\n");
			}
			return builder.ToString();
		}
        #endregion
	}
}
